using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace Krile.Forms.TrayForm
{
    public partial class Tray : Form
    {
        private Notifier ntfy;
        /// <summary>
        /// Notifier
        /// </summary>
        internal Notifier Notify
        {
            get { return ntfy; }
        }

        public Tray()
        {
            InitializeComponent();
            //for Cleanup tray icon
            Application.ApplicationExit += new EventHandler(Application_ApplicationExit);
            this.Enabled = false;
            ntfy = new Notifier(notifyIcon);
            notifyIcon.BalloonTipClicked += new EventHandler(notifyIcon_BalloonTipClicked);
        }

        void notifyIcon_BalloonTipClicked(object sender, EventArgs e)
        {
            if (!Core.FormManager.MainForm.Visible && Core.FormManager.MainForm.IsHandleCreated)
                showMainWnd_Click(sender, e);
        }

#if !PURE_CLR
        Imported.Snippets.WinForms.HotKey showMainHotkey = null;
        Imported.Snippets.WinForms.HotKey showPostHotkey = null;
        void HotkeyInit()
        {
            if (Core.Config.KeyAssign.ShowMainWindowHotKey != Keys.None)
            {
                showMainHotkey = new Krile.Imported.Snippets.WinForms.HotKey(
                    CreateModify(Core.Config.KeyAssign.ShowMainWindowHotKey),
                    Core.Config.KeyAssign.ShowMainWindowHotKey & Keys.KeyCode);
                showMainHotkey.HotKeyPush += new EventHandler(showMainHotkey_HotKeyPush);
            }
            if (Core.Config.KeyAssign.ShowPostBoxHotKey != Keys.None)
            {
                showPostHotkey = new Krile.Imported.Snippets.WinForms.HotKey(
                    CreateModify(Core.Config.KeyAssign.ShowPostBoxHotKey),
                    Core.Config.KeyAssign.ShowPostBoxHotKey & Keys.KeyCode);
                showPostHotkey.HotKeyPush += new EventHandler(showPostHotkey_HotKeyPush);
            }
        }

        private Imported.Snippets.WinForms.MOD_KEY CreateModify(Keys key)
        {
            Imported.Snippets.WinForms.MOD_KEY mod = (Imported.Snippets.WinForms.MOD_KEY)0;
            if ((key & Keys.Alt) == Keys.Alt)
                mod |= Krile.Imported.Snippets.WinForms.MOD_KEY.ALT;
            if ((key & Keys.Shift) == Keys.Shift)
                mod |= Krile.Imported.Snippets.WinForms.MOD_KEY.SHIFT;
            if ((key & Keys.Control) == Keys.Control)
                mod |= Krile.Imported.Snippets.WinForms.MOD_KEY.CONTROL;
            return mod;
        }

        void Application_ThreadExit(object sender, EventArgs e)
        {
            if (showPostHotkey != null)
                showPostHotkey.Dispose();
            showPostHotkey = null;
            if (showMainHotkey != null)
                showMainHotkey.Dispose();
            showMainHotkey = null;
        }



#else
        void HotkeyInit() { }

        void Application_ThreadExit(object sender, EventArgs e) { }
#endif
        public void Init()
        {
            this.Enabled = true;
            notifyIcon.Visible = true;
            notifyIcon.ContextMenuStrip = trayContext;
            notifyIcon.MouseClick += new MouseEventHandler(notifyIcon_MouseClick);
            HotkeyInit();
            Application.ThreadExit += new EventHandler(Application_ThreadExit);
            ntfy.InitWindowRelation();
        }

        void showMainHotkey_HotKeyPush(object sender, EventArgs e)
        {
            showMainWnd_Click(sender, e);
        }

        void showPostHotkey_HotKeyPush(object sender, EventArgs e)
        {
            showPostbox_Click(sender, e);
        }

        void notifyIcon_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (Core.Config.Behavior.TrayClickToShowPostBox)
                    showPostbox_Click(sender, e);
                else
                    showMainWnd_Click(sender, e);
            }
        }

        void Application_ApplicationExit(object sender, EventArgs e)
        {
            //Delete tray icon
            try
            {
                notifyIcon.Visible = false;
                this.Dispose();
            }
            catch (ObjectDisposedException) { }
        }

        private void trayContext_Opening(object sender, CancelEventArgs e)
        {
            if (Core.FormManager.MainForm == null)
                return;

            if (Core.FormManager.MainForm.Visible)
                showMainWnd.Text = Lang.Tray.MainWindow_Hide;
            else
                showMainWnd.Text = Lang.Tray.MainWindow_Show;
            if (Core.Config.Behavior.TrayClickToShowPostBox)
            {
                showMainWnd.Font = new Font(showMainWnd.Font, FontStyle.Regular);
                showPostbox.Font = new Font(showPostbox.Font, FontStyle.Bold);
            }
            else
            {
                showMainWnd.Font = new Font(showMainWnd.Font, FontStyle.Bold);
                showPostbox.Font = new Font(showPostbox.Font, FontStyle.Regular);
            }
            silentMode.Checked = Core.Config.State.SilentMode;
        }

        private void showMainWnd_Click(object sender, EventArgs e)
        {
            ntfy.SetNormalStateIcon();
            if (Core.FormManager.MainForm.Visible)
                Core.FormManager.MainForm.Hide();
            else
                Core.FormManager.MainForm.Show();
            if (Core.FormManager.MainForm.Visible)
            {
                if (Core.FormManager.MainForm.WindowState == FormWindowState.Minimized)
                    Core.FormManager.MainForm.WindowState = FormWindowState.Normal;
                Core.FormManager.MainForm.Focus();
                Core.FormManager.MainForm.BringToFront();
                Core.FormManager.MainForm.Activate();
            }
        }

        Dialogs.Popup.Postbox pb = null;
        private void showPostbox_Click(object sender, EventArgs e)
        {
            if (pb != null)
            {
                pb.Close();
                pb = null;
            }
            pb = new Krile.Forms.Dialogs.Popup.Postbox();
            pb.FormClosed += new FormClosedEventHandler(pb_FormClosed);
            pb.FormClosing += new FormClosingEventHandler(pb_FormClosing);
            if (Core.Config.State.PostboxRect != Rectangle.Empty)
            {
                pb.StartPosition = FormStartPosition.Manual;
                pb.Location = Core.Config.State.PostboxRect.Location;
                pb.Size = Core.Config.State.PostboxRect.Size;
            }
            pb.Show();
        }

        void pb_FormClosing(object sender, FormClosingEventArgs e)
        {
            Core.Config.State.PostboxRect = new Rectangle(pb.Location, pb.Size);
        }

        void pb_FormClosed(object sender, FormClosedEventArgs e)
        {
            pb = null;
        }

        private void silentMode_Click(object sender, EventArgs e)
        {
            Core.FormManager.MainForm.SetSilentMode(!Core.Config.State.SilentMode);
        }

        private void showConfig_Click(object sender, EventArgs e)
        {
            if (Core.FormManager.MainForm.Visible)
            {
                Core.FormManager.MainForm.ShowConfig();
            }
            else
            {
                using (var cfg = new Forms.ConfigForm.Config())
                {
                    cfg.ShowDialog();
                }
            }
        }

        private void exit_Click(object sender, EventArgs e)
        {
            this.BeginInvoke(new Action(() => Core.ExitApp()));
        }

    }

    internal class Notifier
    {
        private NotifyIcon notify;
        private Icon currentIcon = null;

        #region Constant values
        //Constant values
        private const string DEFAULT = "default.ico";
        private const string RECVNEW = "new.ico";
        private const string NOTICE = "notice.ico";
        private const string REPLY = "reply.ico";
        private const string SILENT = "silent.ico";
        private const string ERROR = "error.ico";
        private const string RECVNEWWAV = "new.wav";
        private const string REPLYWAV = "reply.wav";
        private const string NOTIFYWAV = "notify.wav";
        #endregion

        internal enum IconState { Default, RecvNew, Notice, Reply, Silent, Error };
        internal enum SoundState {RecvNewWav, ReplyWav, NotifyWav};

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="ni"></param>
        internal Notifier(NotifyIcon ni)
        {
            notify = ni;
            SetNormalStateIcon();
        }

        internal void InitWindowRelation()
        {
            Core.FormManager.MainForm.VisibleChanged += new EventHandler(MainForm_VisibleChanged);
        }

        internal string GetIconFile(IconState state)
        {
            switch (state)
            {
                case IconState.Default:
                    return DEFAULT;
                case IconState.Error:
                    return ERROR;
                case IconState.Notice:
                    return NOTICE;
                case IconState.RecvNew:
                    return RECVNEW;
                case IconState.Reply:
                    return REPLY;
                case IconState.Silent:
                    return SILENT;
                default:
                    return null;
            }
        }

        internal string GetSoundFile(SoundState sound)
        {
            switch (sound)
            {
                case SoundState.NotifyWav:
                    return Path.Combine(Define.AppPath, Path.Combine(Define.ResourceDir, NOTIFYWAV));
                case SoundState.RecvNewWav:
                    return Path.Combine(Define.AppPath, Path.Combine(Define.ResourceDir, RECVNEWWAV));
                case SoundState.ReplyWav:
                    return Path.Combine(Define.AppPath, Path.Combine(Define.ResourceDir, REPLYWAV));
                default:
                    return null;
            }
        }

        volatile bool noticing = false;
        void MainForm_VisibleChanged(object sender, EventArgs e)
        {
            if (Core.FormManager.MainForm.Visible)
            {
                noticing = false;
                SetNormalStateIcon();
            }
        }

        private void IconDispose()
        {
            if (currentIcon == null) return;
            currentIcon.Dispose();
            currentIcon = null;
        }

        /// <summary>
        /// Get icon by filename
        /// </summary>
        /// <param name="fname">file name</param>
        /// <returns>icon resource</returns>
        private Icon GetIcon(string fname)
        {
            return new Icon(
                Path.Combine(Define.AppPath,
                Path.Combine(Define.ResourceDir,fname))
            );
        }

        /// <summary>
        /// Set icon by filename
        /// </summary>
        /// <param name="fname">file name</param>
        internal void SetIcon(string fname)
        {
            SetIcon(fname, true);
        }

        /// <summary>
        /// Set icon with window state minding
        /// </summary>
        /// <param name="filename">file name</param>
        /// <param name="changeIcoWhenWindowShowing">do change icon when window showing</param>
        internal void SetIcon(string filename, bool changeIcoWhenWindowShowing)
        {
            if ((Core.FormManager.MainForm != null && !Core.FormManager.MainForm.Visible) || changeIcoWhenWindowShowing)
            {
                IconDispose();
                currentIcon = GetIcon(filename);
                noticing = !changeIcoWhenWindowShowing;
                notify.Icon = currentIcon;
            }
        }

        /// <summary>
        /// Normal state icon set (End notify state)
        /// </summary>
        internal void SetNormalStateIcon()
        {
            if (noticing)
                return;
            else if (Core.Config.State.SilentMode)
                SetIcon(SILENT);
            else
                SetIcon(DEFAULT);
        }

        /// <summary>
        /// show popup
        /// </summary>
        internal void Popup(int timeout, string tipTitle, string tipText, ToolTipIcon icon)
        {
            if (!Core.Config.Notification.ShowBalloonOnStatusReceived ||
                (Core.Config.Notification.CancelBalloonOnWindowShown && Core.FormManager.MainForm.Visible))
                return;
            notify.Visible = true;
            notify.ShowBalloonTip(0, tipTitle, tipText, icon);
        }
    }
}